﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlServerCe;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Universe.SimpleQueue.Samples;

namespace Universe.SimpleQueue.Tests
{
    internal class Env
    {
        public static string ConnectionString
        {
            get
            {
                SqlConnectionStringBuilder b = new SqlConnectionStringBuilder
                {
                    DataSource = "(local)",
                    InitialCatalog = "SimpleQueue",
                    ApplicationName = "SimpleQueue Tests",
                    IntegratedSecurity = true,
                    PacketSize = 32768,
                    Pooling = true,
                    PersistSecurityInfo = false,
                };

                return LocalDBConnection.ConnectionString;
                return b.ConnectionString;
            }
        }

        private static int Counter = 0;

        public static readonly Func<SimpleQueue.IConnectionInfo> Connection = () =>
        {
            var con = new SqlConnection(ConnectionString);
            con.Open();
            return new ConnectionInfo() {Connection = con, Transaction = null};
        };

        public static readonly Func<SimpleQueue.IConnectionInfo> SqlServer_With_ReadCommitted_Isolated_Transaction = () =>
        {
            var con = new SqlConnection(ConnectionString);
            con.Open();
            var tran = con.BeginTransaction(IsolationLevel.ReadCommitted);
            return new ConnectionInfo() { Connection = con, Transaction = tran };
        };

        public static readonly Func<SimpleQueue.IConnectionInfo> SqlServer_With_Serializable_Isolated_Transaction = () =>
        {
            var con = new SqlConnection(ConnectionString);
            con.Open();
            var tran = con.BeginTransaction(IsolationLevel.Serializable);
            return new ConnectionInfo() { Connection = con, Transaction = tran };
        };

        public static readonly Func<SimpleQueue.IConnectionInfo> SqlServer_With_RepeatableRead_Isolated_Transaction = () =>
        {
            var con = new SqlConnection(ConnectionString);
            con.Open();
            var tran = con.BeginTransaction(IsolationLevel.RepeatableRead);
            return new ConnectionInfo() { Connection = con, Transaction = tran };
        };


        private static string ConnectionStringCE
        {
            get { return _ConnectionStringCE.Value; }
        }

        private static Lazy<string> _ConnectionStringCE = new Lazy<string>(() =>
        {
            var path = Path.GetTempPath();
            var file = Path.Combine(Path.GetTempPath(), "SimpleQueue\\StressDatabase.sdf");

            SqlCeConnectionStringBuilder b = new SqlCeConnectionStringBuilder()
            {
                DataSource = file,
                MaxDatabaseSize = 4000,
                MaxBufferSize = 1024,
                FileMode = "Read Write",
                TempFileMaxSize = 4000,
                DefaultLockTimeout = 9000,
            };

            string mutexName = "SQLCE_" + file;
            using(mutexName.CrossProcessLock())
            {
                if (!File.Exists(file))
                {

                    if (!Directory.Exists(Path.GetDirectoryName(file)))
                        Directory.CreateDirectory(Path.GetDirectoryName(file));

                    SqlCeEngine eng = new SqlCeEngine(b.ToString());
                    eng.CreateDatabase();
                    using (SqlCeConnection con = new SqlCeConnection(b.ToString()))
                    {
                        con.Open();
                        DDLResources.ApplyDDL(con, DDLResources.SqlCeDdlName);
                        Trace.WriteLine("CE DB: " + file);
                        Trace.WriteLine(b.ToString());
                    }

                    AppDomain.CurrentDomain.DomainUnload += (sender, args) =>
                    {
                        // if (File.Exists(file)) File.Delete(file);
                    };

                }
            }


            return b.ToString();
        }, LazyThreadSafetyMode.ExecutionAndPublication);

        public static readonly Func<SimpleQueue.IConnectionInfo> SQLCE_With_Explicit_ReadCommitted_Isolatated_Transactions = () =>
        {
            var con = new SqlCeConnection(ConnectionStringCE);
            con.Open();
            // SERIALIZABLE doesnt work properly :(
            var tran = con.BeginTransaction(IsolationLevel.ReadCommitted);
            return new ConnectionInfo() { Connection = con, Transaction = tran };
        };

        public static readonly Func<SimpleQueue.IConnectionInfo> SQLCE_With_Explicit_Serializable_Isolatated_Transactions = () =>
        {
            var con = new SqlCeConnection(ConnectionStringCE);
            con.Open();
            // SERIALIZABLE doesnt work properly :(
            var tran = con.BeginTransaction(IsolationLevel.Serializable);
            return new ConnectionInfo() { Connection = con, Transaction = tran };
        };

        public static readonly Func<SimpleQueue.IConnectionInfo> ConnectionCE = () =>
        {
            var con = new SqlCeConnection(ConnectionStringCE);
            con.Open();
            return new ConnectionInfo() { Connection = con };
        };

        private class ConnectionInfo : Universe.SimpleQueue.SimpleQueue.IConnectionInfo
        {
            public DbConnection Connection { get; set; }
            public DbTransaction Transaction { get; set; }
        }

    }
}
